package bigoo.common.communication;

import static java.util.logging.Logger.GLOBAL_LOGGER_NAME;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

import bigoo.common.PeerInfo;
import bigoo.peer.PeerFailureInterested;

public abstract class AbstractCommunication {

	protected Logger logger = Logger.getLogger(GLOBAL_LOGGER_NAME);
	protected List<PeerFailureInterested> peerFailuresInteresteds = new LinkedList<PeerFailureInterested>();
	protected Lock monitor = new ReentrantLock();
	protected MessageBuilderFactory builderFactory = MessageBuilderFactory.getInstance();
	protected List<MessageReceiver> receivers = new LinkedList<MessageReceiver>();

	/**
	 * Sends a message to the given destination.
	 * 
	 * @param message
	 *            the message to be sent.
	 * @param destPeer
	 *            the destination address.
	 * @throws IOException
	 *             If an IO error occurs whiling performing the operation.
	 */
	public abstract void sendMessage(Message message, PeerInfo destPeer) throws IOException;

	/**
	 * Starts the communication layer. If it's already started or the received
	 * isn't defined, nothing happens.
	 */
	public abstract void start();

	/**
	 * Closes the connection with the given peer
	 */
	public abstract void closeConnection(PeerInfo peer);

	public final void addPeerInterested(PeerFailureInterested interested) {
		this.peerFailuresInteresteds.add(interested);
	}

	public final void addReceiver(MessageReceiver receiver) {
		this.receivers.add(receiver);
	}

	protected final Message getMessage(String rawMessage) throws UnknownMessageException, InvalidMessageException {
		String msgID = AbstractMessage.parseMessageID(rawMessage);
		Message msg = this.builderFactory.getBuilder(msgID).parseMessage(rawMessage);
		return msg;
	}

	protected final void deliverMessage(Message msg) {
	    for (MessageReceiver receiver : this.receivers) {
		receiver.processMessage(msg);
	    }
	}

	protected final void fireFailure(String peerID) {
		for(PeerFailureInterested interested: this.peerFailuresInteresteds) {
			interested.peerFailed(peerID);
		}
	}
}